package gbench.sandbox.tuple;

import org.junit.jupiter.api.Test;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.*;

import gbench.common.matlib.MatlibCanvas;
import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.Node;

import static gbench.common.matlib.MatlibCanvas.println;

/**
 * LISP的思想
 * @author gbench
 *
 */
public class JunitLisp2 {

    public static class Lisp<T> extends LinkedList<T> {
        private static final long serialVersionUID = 1L;

        /**
         * 空值构造函数
         */
        public Lisp() {

        }

        /**
         * 列表构造函数
         * 
         * @param coll
         */
        public Lisp(Collection<T> coll) {
            this.addAll(coll);
        }

        /**
         * 数值结算
         * 
         * @return
         */
        @SuppressWarnings("unchecked")
        public Double evaluate() {
            final var car = this.pop().toString();
            final var cdr = this.stream()
                    .map(e -> e instanceof Lisp ? ((Lisp<Object>) e).evaluate() : IRecord.obj2dbl().apply(e));
            switch (car) {
            case "+":
                return cdr.reduce((a, b) -> a + b).get();
            case "-":
                return cdr.reduce((a, b) -> a - b).get();
            case "*":
                return cdr.reduce((a, b) -> a * b).get();
            case "/":
                return cdr.reduce((a, b) -> a / b).get();
            default:
                return null;
            }
        }

        /**
         * 正序构建
         * 
         * @param <T>
         * @return
         */
        @SuppressWarnings("unchecked")
        public static <T> Collector<T, ?, Lisp<T>> lispclc() {
            return Collector.of((Supplier<Lisp<T>>) Lisp::new, Lisp::add, (left, right) -> {
                left.addAll(right);
                return left;
            }, e -> e.size() == 1 && e.get(0) instanceof Lisp ? (Lisp<T>) e.get(0) : e);
        }

        /**
         * 倒序构建
         * 
         * @param <T>
         * @return
         */
        @SuppressWarnings("unchecked")
        public static <T> Collector<T, ?, Lisp<T>> lispclc2() {
            return Collector.of((Supplier<Lisp<T>>) Lisp::new, Lisp::addFirst, (left, right) -> {
                left.addAll(right);
                return left;
            }, e -> e.size() == 1 && e.get(0) instanceof Lisp ? (Lisp<T>) e.get(0) : e);
        }
    }

    /**
     * 列表思想 前缀表达式(波兰式)
     */
    @Test
    public void foo() {
        final var statement = "(+ 1 (* 2 (/ 3 4) 2) 5 6)";
        final var BEGIN = "(";
        final var END = ")";
        @SuppressWarnings("unchecked")
        final var root = (Lisp<Object>) Stream.of(statement.split("")).filter(e -> !e.matches("\\s+"))
                .reduce(new Stack<Object>(), (stack, elem) -> {
                    stack.push((END.equals(elem))
                            ? Stream.iterate(stack.pop(), e -> !(BEGIN.equals(e) || stack.empty()), e -> stack.pop())
                                    .collect(Lisp.lispclc2())
                            : elem);
                    return stack;
                }, (a, b) -> b).pop();

        println(root,"---------->",root.evaluate());
    }

    /**
     * 列表实践
     */
    @Test
    public void bar() {
        final var statement = "(1+2)+(3*4)+(5/6)";
        final var BEGIN = "(";
        final var END = ")";
        final Predicate<Object> isop = s -> "+-*/".contains(s.toString());

        @SuppressWarnings("unchecked")
        final Function<Object[], Lisp<Object>> reduce = data -> (Lisp<Object>) Stream.of(data)
                .reduce(new Stack<Object>(), (stack, elem) -> {
                    final var node = (isop.test(elem) || stack.empty()) ? elem
                            : Stream.of(stack.pop(), stack.pop(), elem).collect(Lisp.lispclc());
                    stack.push(node);
                    return stack;
                }, (a, b) -> a).pop(); // 规约函数 没有括号

        final Function<Object[], Lisp<Object>> handle = data -> reduce
                .apply(Stream.of(data).reduce(new Stack<Object>(), (stack, elem) -> {
                    stack.push(END.equals(elem) 
                            ? reduce.apply(Stream
                                    .iterate(stack.pop(), e -> !(BEGIN.equals(e) || stack.empty()), e -> stack.pop()).toArray())
                            : elem);
                    return stack;
                }, (a, b) -> a).toArray()); // 数据生成函数 函数有括号
        final var lisp = handle.apply(statement.split("")); // 数据处理

        println(lisp,"---------->",lisp.evaluate());
    }
    
    /**
     * 树结构
     */
    @SuppressWarnings("unchecked")
    @Test
    public void tree() {
        final var line = "(+ 1 (* 2 3) 4 (+ 5 6 (*  7 8) 9) 0)";
        final var BEGIN = "("; // 分组开始符号
        final var END = ")"; // 分组结束符号
        final Collector<Object, ?, LinkedList<Object>> llclc = Collector.of(LinkedList::new, LinkedList::addFirst,
                (a, b) -> a, e -> e.size() == 1 && e.get(0) instanceof LinkedList ? (LinkedList<Object>) e.get(0) : e); // LinkedList                                                                                                                        // 归集器
        final var root = Stream.of(line.split("")).filter(e -> !e.matches("\\s*"))
            .collect(Collector.of(LinkedList::new, (stack, elem) -> { // 数据压栈
                stack.push( END.equals(elem)
                    ? Stream.iterate(stack.pop(), e -> !(BEGIN.equals(e) || stack.isEmpty()), e -> stack.pop()).collect(llclc)
                    : elem);
            }, (a, b) -> a, e -> e.size() == 1 && e.get(0) instanceof LinkedList ? (LinkedList<Object>) e.get(0) : e));
        
        final Object END_FLAG = null; // 列表末尾标记
        final var stack = new LinkedList<Object>(); // 层级化运算堆栈
        final Map<Integer, Node<Object>> levelMap = new TreeMap<>(); // 层级化节点映射缓存
        final var rootNode = new Node<Object>("/"); // 根节点
        
        stack.push(root); // 根节点入栈
        Integer level = 0; // 根节点层级
        levelMap.put(level, rootNode); // 标记根节点层级：0

        println("根节点",root);
        while (!stack.isEmpty()) {
            final var elem = stack.pop(); //  提取数据
            
            if (elem instanceof List) {
                level++;
                stack.push(END_FLAG); // 加入结束标记
                final var reversed = new LinkedList<Object>();
                ((List<Object>) elem).forEach(reversed::addFirst); // 调转列表
                reversed.forEach(stack::push);
            } else if (elem == END_FLAG) { // 遭遇结束标记
                level--;
            } // if

            if (elem != null) { // 建立结构关系
                final var parent = levelMap.get(level - 1); // 提取父节点
                final var node = new Node<>(elem);
                levelMap.put(level, node); // 设置节点层次
                if (parent != null) {
                    parent.addChild(node);
                } // if parent
            } // if
        } // while

        // 结构关系打印
        rootNode.forEach(node -> {
            MatlibCanvas.println(" | ".repeat(node.getLevel()-1) + node);
        });
        
    } // tree

}
